﻿using System.Drawing;
namespace UnityEditor.Controls.MenuControl
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    using UnityEditor.Controls.MenuControl.ViewModel;
    using UnityEngine.Core;
    using System.Windows.Data;
    using System.Windows.Media;

    /// <summary>
    /// Interaction logic for MenuControl.xaml
    /// </summary>
    public partial class MenuControl : UserControl, INotifyPropertyChanged
    {
        private List<Type> typesToParse;

        private readonly System.Windows.Media.Color PRESSED_COLOR = System.Windows.Media.Color.FromRgb(173, 255, 47);
        private readonly System.Windows.Media.Color NORMAL_COLOR = System.Windows.Media.Color.FromRgb(255, 255, 255);

        public MenuControl()
        {
            this.InitializeComponent();

            this.Init();
        }
        
        public event PropertyChangedEventHandler PropertyChanged;

        public List<Type> TypesToParse
        {
            get
            {
                return typesToParse;
            }
            set
            {
                typesToParse = value;
                this.NotifyPropertyChanged(() => this.TypesToParse);
            }
        }

        public void AnalyzeTypes()
        {
            if (TypesToParse == null || TypesToParse.Count == 0)
                return;

            foreach (Type type in TypesToParse)
            {
                foreach (MethodInfo methodInfo in type.GetMethods())
                {
                    if (methodInfo.IsStatic == false)
                        continue;

                    foreach (object attribute in methodInfo.GetCustomAttributes(false))
                    {
                        if (attribute is MenuItemAttribute)
                        {
                            AddMenuItem(attribute as MenuItemAttribute, methodInfo);
                        }
                    }
                }
            }
        }

        public void NotifyPropertyChanged<TProperty>(Expression<Func<TProperty>> property)
        {
            var lambda = (LambdaExpression)property;
            MemberExpression memberExpression;
            if (lambda.Body is UnaryExpression)
            {
                var unaryExpression = (UnaryExpression)lambda.Body;
                memberExpression = (MemberExpression)unaryExpression.Operand;
            }
            else
                memberExpression = (MemberExpression)lambda.Body;

            this.OnPropertyChanged(memberExpression.Member.Name);
        }

        private void AddMenuItem(MenuItemAttribute attribute, MethodInfo methodInfo)
        {
            int length = attribute.Length;
            MenuItem[] menus = new MenuItem[length];
            MenuItem item = null;

            for (int index = 0; index < length; index++)
            {
                string key = attribute[index];
                if (index == 0)
                {
                    menus[index] = FindItemWithKey(Menu.Items, key);
                    if (menus[index] == null)
                    {
                        menus[index] = new MenuItem();
                        menus[index].Header = key;
                        Menu.Items.Add(menus[index]);
                    }
                }
                else
                {
                    menus[index] = FindItemWithKey(menus[index - 1].Items, key);
                    if (menus[index] == null)
                    {
                        menus[index] = new MenuItem();
                        menus[index].Header = key;
                        menus[index - 1].Items.Add(menus[index]);
                    }
                }

                if (menus[index] != null)
                    item = menus[index];
            }

            if (item != null)
            {
                item.Click += new RoutedEventHandler(new MenuItemEventHandle(methodInfo).RoutedEventHandlerMethod);
            }
        }

        private MenuItem FindItemWithKey(ItemCollection collection, string key)
        {
            foreach (MenuItem item in collection)
            {
                if (item.Header.ToString() == key)
                    return item;
            }

            return null;
        }

        private void Init()
        {
            this.TypesToParse = new List<Type>();
            //this.TypesToParse.Add(typeof(FileMenuItem));
            this.AnalyzeTypes();
            this.UpdateLayout();

            System.Windows.Data.Binding binding = new System.Windows.Data.Binding("GameStatus") { Source = Workspace.Instance };
            BindingOperations.SetBinding(this, MenuControl.GameStatusProperty, binding);
            Workspace.Instance.GameStatus = GameStatus.Editor;
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #region GameStatus
        public static readonly DependencyProperty GameStatusProperty =
            DependencyProperty.Register("GameStatus", typeof(GameStatus), typeof(MenuControl),
                new FrameworkPropertyMetadata(GameStatus.Pause, new PropertyChangedCallback(_OnStatusChanged)));

        public GameStatus GameStatus
        {
            get { return (GameStatus)GetValue(GameStatusProperty); }
            set { SetValue(GameStatusProperty, value); }
        }

        static void _OnStatusChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((MenuControl)sender)._OnStatusChanged(e);
        }

        protected virtual void _OnStatusChanged(DependencyPropertyChangedEventArgs e)
        {
            playButton.Background = new SolidColorBrush(NORMAL_COLOR);
            pauseButton.Background = new SolidColorBrush(NORMAL_COLOR);
            stopButton.Background = new SolidColorBrush(NORMAL_COLOR);

            GameStatus value = (GameStatus)e.NewValue;
            switch (value)
            {
                case GameStatus.Editor:
                    stopButton.Background = new SolidColorBrush(PRESSED_COLOR);
                    break;
                case GameStatus.Startup:
                    playButton.Background = new SolidColorBrush(PRESSED_COLOR);
                    break;
                case GameStatus.Play:
                    playButton.Background = new SolidColorBrush(PRESSED_COLOR);
                    break;
                case GameStatus.Pause:
                    pauseButton.Background = new SolidColorBrush(PRESSED_COLOR);
                    break;
                case GameStatus.PlayInWindow:
                    playButton.Background = new SolidColorBrush(PRESSED_COLOR);
                    break;
                default:
                    throw new Exception("Error in status changed");
            }
        }
        #endregion
    }
}
